package com.physics.mps.module.abaqus;

import com.physics.mps.entity.vo.*;
import com.physics.mps.module.util.PyUtils;
import com.physics.mps.entity.vo.*;
import lombok.Setter;

import java.util.List;

/**
 * Abaqus计算模块：热力耦合
 *
 */
@Setter
public class AbaqusCoupledTempDisplacementHandler extends AbstractAbaqusComputeHandler {

    /**
     * 对流换热设置参数
     */
    private List<InteractionVo> interactions;

    /**
     * 温度场设置参数
     */
    private List<TemperatureFieldVo> temperatureFieldVos;

    /**
     * 传热分析分析步参数
     */
    private AbaqusCoupledTempDisplacementStepVo tempDisplacementStepVo;

    /**
     * 边界条件参数
     */
    private List<AbaqusBoundaryVo> boundaryVos;

    /**
     * 初始温度参数
     */
    private String initTemperature;

    /**
     * 热通量
     */
    private List<AbaqusBodyHeatFluxVo> bodyHeatFluxesVos;


    /**
     * 设置全局参数
     * @param coupledTempDisplacementParam 通过前端传入并解析的参数
     * @return 脚本拼接的处理器
     */
    @Override
    public AbstractAbaqusComputeHandler setAbaqusComputeParam(AbaqusComputeParam coupledTempDisplacementParam) {
        this.abaqusComputeParam = coupledTempDisplacementParam;

        if (coupledTempDisplacementParam instanceof AbaqusCoupledTempDisplacementParam) {
            AbaqusCoupledTempDisplacementParam specificParam = (AbaqusCoupledTempDisplacementParam) coupledTempDisplacementParam;

            this.parts = specificParam.getParts();

            this.partNames = specificParam.getPartNames();

            this.meshVo = specificParam.getMeshVo();

            this.jobVo = specificParam.getJobVo();

            this.jobVo.setVariableLabel("NT11");

            this.jobVo.setOutputPosition("NODAL");

            this.tempDisplacementStepVo = specificParam.getTempDisplacementStepVo();

            this.boundaryVos = specificParam.getBoundaryVos();

            super.tieVos = specificParam.getTieVos();

            this.initTemperature = specificParam.getInitTemperature();

            this.interactions = specificParam.getInteractions();

            this.temperatureFieldVos = specificParam.getTemperatureFieldVos();

            this.bodyHeatFluxesVos = specificParam.getBodyHeatFluxesVos();

            this.board = specificParam.getBoard();

            this.setComputeParam = true;
        }

        return this;
    }

    /**
     * 创建 STEP 命令
     * @param builder
     */
    @Override
    public void createStepImpl(StringBuilder builder) {
        builder
                .append(this.createMdbModelsCommand("Model-1"))
                .append(".CoupledTempDisplacementStep(name='Step-1', previous='Initial'")
                .append(", timePeriod=").append(this.tempDisplacementStepVo.getTimePeriod())
                .append(", maxNumInc=").append(this.tempDisplacementStepVo.getMaxNumInc())
                .append(", initialInc=").append(this.tempDisplacementStepVo.getInitialInc())
                .append(", minInc=").append(this.tempDisplacementStepVo.getMinInc())
                .append(", maxInc=").append(this.tempDisplacementStepVo.getMaxInc())
                .append(", deltmx=").append(this.tempDisplacementStepVo.getDelmx()).append(")")
                .append(PyUtils.WRAP)
        ;
    }


    /**
     * 创建 分析步以及场 命令
     * @param builder
     */
    @Override
    public void createStepAndFieldImpl(StringBuilder builder) {
        //5.创建分析步
        builder.append(this.createStep());

        //6.创建绑定(移至AbstractAbaqusComputeHandler)
        //builder.append(this.createTieCommand());

        //7.对流换热和初始温度
        builder.append(this.createInteractionCommand());

        builder.append(this.createTemperatureCommand());

        //8.热通量
        builder.append(this.createHeatFluxCommand());
    }

    // ~ Variable & Constant
    // ========================================================================================================


    // ~ Public method
    // ========================================================================================================


    // ~ Override method
    // ========================================================================================================
    /**
     * 创建边界条件命令
     * @param builder
     */
    @Override
    public void createBoundaryCommandImpl(StringBuilder builder) {

    }


    /**
     * 创建输出命令
     * @param builder
     */
    @Override
    public void createOutputCommandImpl(StringBuilder builder) {

    }

    /**
     * 创建设置网格类型命令
     * @param builder
     */
    @Override
    public void createElemTypeCommandImpl(StringBuilder builder) {
        builder.append("elemType1 = mesh.ElemType(elemCode=C3D8T, elemLibrary=STANDARD, secondOrderAccuracy=OFF, distortionControl=DEFAULT)").append(PyUtils.WRAP);
        builder.append("elemType2 = mesh.ElemType(elemCode=C3D6T, elemLibrary=STANDARD)").append(PyUtils.WRAP);
        builder.append("elemType3 = mesh.ElemType(elemCode=C3D4T, elemLibrary=STANDARD)").append(PyUtils.WRAP);

    }

    /**
     * 创建设置导出命令
     * @param builder
     */
    @Override
    public void createExportCommandImpl(StringBuilder builder) {
        //循环读取结果场的不同部件的最大值和最小值
        builder.append("def loopAndCompare(instance_name, max_val, min_val):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("field_variable = lastFrame.fieldOutputs['NT11'].getSubset(region=instance[instance_name])").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("fieldValues = field_variable.values").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("for v in fieldValues:").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("if (v.data > max_val):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(3)).append("max_val = v.data").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("if (v.data < min_val):").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(3)).append("min_val = v.data").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("return max_val, min_val").append(PyUtils.WRAP);

        //读取odb文件中的结果场
        builder.append("from odbAccess import openOdb").append(PyUtils.WRAP);
        builder.append("from textRepr import *").append(PyUtils.WRAP);
        builder.append("my_odb = openOdb(r\"").append(this.workDir).append("\\\\").append(jobVo.getJobName()).append(".odb\")").append(PyUtils.WRAP);
        builder.append("file = open('").append(this.workDir).append("\\\\PNG\\\\").append(this.jobVo.getJobName()).append(".txt', 'w')").append(PyUtils.WRAP);
        builder.append("lastFrame = my_odb.steps['Step-1'].frames[-1]").append(PyUtils.WRAP);
        builder.append("len = ").append(partNames.size()).append(PyUtils.WRAP);
        builder.append("instance = my_odb.rootAssembly.instances").append(PyUtils.WRAP);

        //将最大值最小值写入文件
        builder.append("instance_name = 'COMPOUND'").append(PyUtils.WRAP);
        builder.append("field_variable=lastFrame.fieldOutputs['NT11'].getSubset(region = instance[instance_name])").append(PyUtils.WRAP);
        builder.append("fieldValues=field_variable.values").append(PyUtils.WRAP);
        builder.append("val=field_variable.values[0].data").append(PyUtils.WRAP);
        builder.append("max_val, min_val = loopAndCompare(instance_name, val, val)").append(PyUtils.WRAP);
        builder.append("file.write(instance_name + ':max_val:' + str(max_val) + '\\n')").append(PyUtils.WRAP);
        builder.append("file.write(instance_name + ':min_val:' + str(min_val) + '\\n')").append(PyUtils.WRAP);
        builder.append("for i in range(1, len) :").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("instance_name = 'COMPOUND-' + str(i)").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(1)).append("if instance_name != \"").append(this.board).append("\" :").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("max_val, min_val = loopAndCompare(instance_name, max_val, min_val)").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("file.write(instance_name + ':max_val:' + str(max_val) + '\\n')").append(PyUtils.WRAP);
        builder.append(PyUtils.RETRACT(2)).append("file.write(instance_name + ':min_val:' + str(min_val) + '\\n')").append(PyUtils.WRAP);
        builder.append("instance_name = \"").append(this.board).append("\"").append(PyUtils.WRAP);
        builder.append("field_variable=lastFrame.fieldOutputs['NT11'].getSubset(region = instance[instance_name])").append(PyUtils.WRAP);
        builder.append("fieldValues=field_variable.values").append(PyUtils.WRAP);
        builder.append("val=field_variable.values[0].data").append(PyUtils.WRAP);
        builder.append("max_val2, min_val2 = loopAndCompare(instance_name, val, val)").append(PyUtils.WRAP);
        builder.append("file.write('BOARD:max_val:' + str(max_val2) + '\\n')").append(PyUtils.WRAP);
        builder.append("file.write('BOARD:min_val:' + str(min_val2) + '\\n')").append(PyUtils.WRAP);
        builder.append("file.close()").append(PyUtils.WRAP);

    }

    // ~ Private method
    // ========================================================================================================
    /**
     * 创建设置对流换热命令
     * @return
     */
    private String createInteractionCommand() {
        StringBuilder builder = new StringBuilder();

        int interactionNum = 1;
        for (InteractionVo interaction : interactions) {
            String partName = interaction.getPartName();
            List<float[]> coordinates = interaction.getCoordinates();
            float[] co = coordinates.get(0);
            float filmCoeff = interaction.getFilmCoeff();
            String sinkTemperature = interaction.getSinkTemperature();

            String facesName = "s" + interactionNum;
            String faceName = "side1Faces" + interactionNum;
            builder.append(facesName)
                    .append("=")
                    .append("a.instances['")
                    .append(partName)
                    .append("'].faces")
                    .append(PyUtils.WRAP);
            builder.append(faceName)
                    .append("=")
                    .append(facesName)
                    .append(".findAt(((").append(co[0]).append(", ")
                    .append(co[1]).append(", ")
                    .append(co[2])
                    .append("), ))")
                    .append(PyUtils.WRAP);

            String regionName = "region" + interactionNum;
            String surfaceName = "sur" + interactionNum;
            builder.append(regionName)
                    .append("=")
                    .append("a.Surface(side1Faces=")
                    .append(faceName)
                    .append(", name='")
                    .append(surfaceName)
                    .append("')")
                    .append(PyUtils.WRAP);
            builder
                    .append(this.createMdbModelsCommand("Model-1"))
                    .append(".FilmCondition(name='Int-convecton").append(interactionNum).append("', " + "createStepName='Step-1', surface=")
                    .append(regionName).append(", definition=EMBEDDED_COEFF, ")
                    .append("filmCoeff=")
                    .append(filmCoeff)
                    .append(", filmCoeffAmplitude='', sinkTemperature=")
                    .append(sinkTemperature)
                    .append(", sinkAmplitude='', ")
                    .append("sinkDistributionType=UNIFORM, sinkFieldName='')")
                    .append(PyUtils.WRAP)
            ;
            interactionNum++;
        }
        return builder.toString();
    }

    /**
     * 创建设置温度场命令
     * @return
     */
    private String createTemperatureCommand() {
        StringBuilder builder = new StringBuilder();
        int temperatureNum = 1;
        for (TemperatureFieldVo field : temperatureFieldVos) {
            String partName = field.getPartName();
            List<float[]> coordinates = field.getCoordinates();
            float temperature = field.getTemperature();
            builder.append("c = ").append("a.instances['").append(partName).append("'].cells").append(PyUtils.WRAP);
            builder.append("i = 2 ** len(c) - 1").append(PyUtils.WRAP);
            builder.append("hexstr = \"%x\" % i").append(PyUtils.WRAP);
            builder.append("str1 = '[#' + hexstr + ' ]'").append(PyUtils.WRAP);
            String cellName = "cells" + temperatureNum;
            builder.append(cellName).append(" = c.getSequenceFromMask(mask=(str1, ), )")
                    .append(PyUtils.WRAP);
            String regionName = "region" + temperatureNum;
            String setName = "sets" + temperatureNum;
            builder.append(regionName)
                    .append("=a.Set(cells=")
                    .append(cellName)
                    .append(", name='")
                    .append(setName)
                    .append("')")
                    .append(PyUtils.WRAP);
            String fieldName = "field" + temperatureNum;
            builder
                    .append(this.createMdbModelsCommand("Model-1"))
                    .append(".Temperature(name='").append(fieldName).append("', ").append("createStepName='Initial', region=").append(regionName).append(", distributionType=UNIFORM, ").append("crossSectionDistribution=CONSTANT_THROUGH_THICKNESS, magnitudes=(").append(temperature).append(", ))")
                    .append(PyUtils.WRAP)
            ;
            temperatureNum++;
        }
        return builder.toString();
    }

    /**
     * 创建设置热通量命令
     * @return
     */
    private String createHeatFluxCommand() {
        StringBuilder builder = new StringBuilder();
        int i = 0;
        for (AbaqusBodyHeatFluxVo bodyHeatFluxesVo : bodyHeatFluxesVos) {
            builder.append("c = a.instances['")
                    .append(bodyHeatFluxesVo.getPartName())
                    .append("'].cells").append(PyUtils.WRAP);

            // 掩码规律，体的数量为n，则选择所有体的掩码为2^n-1,转换为十六进制输入
            builder.append("i = 2 ** len(c) - 1").append(PyUtils.WRAP);
            builder.append("hexstr = \"%x\" % i").append(PyUtils.WRAP);
            builder.append("str2 = '[#' + hexstr + ' ]'").append(PyUtils.WRAP);
            builder.append("cells = c.getSequenceFromMask(mask=(str2, ), )").append(PyUtils.WRAP);
            builder.append("region = regionToolset.Region(cells=cells)")
                    .append(PyUtils.WRAP);
            builder.append(this.createMdbModelsCommand("Model-1"))
                    .append(".BodyHeatFlux(name='Load-").append(i).append("'")
                    .append(", createStepName='Step-1'")
                    .append(", region=region")
                    .append(", magnitude=").append(bodyHeatFluxesVo.getMagnitude()).append(")")
                    .append(PyUtils.WRAP);
        }
        return builder.toString();
    }

    // ~ Autowired
    // ========================================================================================================


}
